package com.sgzn.sgpay.service.impl;

import com.alibaba.dubbo.common.utils.CollectionUtils;
import com.sgzn.sgpay.enums.AppName;
import com.sgzn.sgpay.enums.OrderStateEnum;
import com.sgzn.sgpay.enums.SeqFlagEnum;
import com.sgzn.sgpay.enums.SgsResponseCode;
import com.sgzn.sgpay.exception.SgpayException;
import com.sgzn.sgpay.model.request.SgsCallBackRequest;
import com.sgzn.sgpay.model.request.SgsUserDiscRuleQueryRequest;
import com.sgzn.sgpay.model.request.SgsUserDiscountRuleQueryRequest;
import com.sgzn.sgpay.model.response.SgsResultResponse;
import com.sgzn.sgpay.model.response.vo.UserDiscountRuleVo;
import com.sgzn.sgpay.persistence.dao.TMainOrderMapper;
import com.sgzn.sgpay.persistence.dao.TPayOrderMapper;
import com.sgzn.sgpay.persistence.dao.TUserAccountMapper;
import com.sgzn.sgpay.persistence.domain.*;
import com.sgzn.sgpay.service.SgsCallBackService;
import com.sgzn.sgpay.service.SgsUserDiscountRuleService;
import com.sgzn.sgpay.util.AmountTransUtil;
import com.sgzn.sgpay.util.SeqUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author huangsenguang
 */
@Slf4j
@Service
@Transactional
public class SgsCallBackServiceImpl implements SgsCallBackService {
    /**
     * 主单
     */
    @Autowired
    private TMainOrderMapper tMainOrderMapper;
    /**
     * 支付单
     */
    @Autowired
    private TPayOrderMapper tPayOrderMapper;

    @Autowired
    private TUserAccountMapper tUserAccountMapper;

    @Resource
    private SgsUserDiscountRuleService sgsUserDiscountRuleService;




    @Override
    public SgsResultResponse<String> deposit(SgsCallBackRequest sgsCallBackRequest) {
        SgsResultResponse<String> sgsResultResponse = new SgsResultResponse();

        String initiationID = sgsCallBackRequest.getInitiationID();
        StringBuffer buffer = null;
        Lock lock = new ReentrantLock();
        lock.lock();
        try {
            //判断 支付是否成功
            if("SUCCESS".equals(sgsCallBackRequest.getReturn_code())){
                log.info("微信回调返回： {}",sgsCallBackRequest.toString());
                //获得 返回的商户订单号
                String outTradeNo = sgsCallBackRequest.getOut_trade_no();
                log.info("微信回调返回商户订单号：{}", outTradeNo);

                if ("SUCCESS".equals(sgsCallBackRequest.getResult_code())){
                    //result_code为SUCCESS
                    buffer = handleSuccess(sgsCallBackRequest, outTradeNo);
                    sgsResultResponse.setErrorCode(SgsResponseCode.C200.getResponseCode());
                    sgsResultResponse.setErrorMsg(SgsResponseCode.C200.getResponseDesc());
                } else {
                    //result_code为FAIL
                    buffer = handleFail(outTradeNo);
                    throw new SgpayException(SgsResponseCode.C_PAY_CALLBACK_ERR.getResponseCode(),SgsResponseCode.C_PAY_CALLBACK_ERR.getResponseDesc());
                }
            }else{
                buffer = new StringBuffer();
                buffer.append("<xml>");
                buffer.append("<return_code>FAIL</return_code>");
                buffer.append("<return_msg>回调接收到失败的信息,微信支付失败</return_msg>");
                buffer.append("<xml>");
                log.error("[{}]微信回调失败return_code={}, return_msg={},response：{}",sgsCallBackRequest.getInitiationID(),
                        sgsCallBackRequest.getReturn_code(),sgsCallBackRequest.getReturn_msg(),buffer.toString());
                throw new SgpayException(SgsResponseCode.C_PAY_CALLBACK_ERR.getResponseCode(),SgsResponseCode.C_PAY_CALLBACK_ERR.getResponseDesc());
            }
        } catch (SgpayException e) {
            log.error("[{}] 支付回调出现异常：{},{}",initiationID,e.getCode(),e.getDesc());
            sgsResultResponse.setErrorCode(e.getCode());
            sgsResultResponse.setErrorMsg(e.getDesc());
        } catch (Exception e) {
            log.error("[{}] 支付回调出现异常：",initiationID,e);
            sgsResultResponse.setErrorCode(SgsResponseCode.C_PAY_CALLBACK_ERR.getResponseCode());
            sgsResultResponse.setErrorMsg(SgsResponseCode.C_PAY_CALLBACK_ERR.getResponseDesc());
        } finally {
            lock.unlock();   //释放锁
        }
        if (buffer != null) {
            sgsResultResponse.setResult(buffer.toString());
        }
        return sgsResultResponse;
    }

    private StringBuffer handleFail(String outTradeNo) {
        //更新主订单
        TMainOrderExample tMainOrderExample = new TMainOrderExample();
        TMainOrderExample.Criteria criteria = tMainOrderExample.createCriteria();
        criteria.andOrderIdEqualTo(outTradeNo);
        List<TMainOrder> tMainOrders = this.tMainOrderMapper.selectByExample(tMainOrderExample);
        TMainOrder mainOrder = tMainOrders.get(0);
        //修改支付状态
        mainOrder.setOrderState(OrderStateEnum.SM_FAIL.getCode());
        mainOrder.setUpdatedAt(new Date());
        int sqlRowMainOrder = 0;
        sqlRowMainOrder = this.tMainOrderMapper.updateByPrimaryKeySelective(mainOrder);

        //更新支付单
        TPayOrderExample tPayOrderExample = new TPayOrderExample();
        TPayOrderExample.Criteria criteria1 = tPayOrderExample.createCriteria();
        criteria1.andOrderIdEqualTo(outTradeNo);
        List<TPayOrder> tPayOrders = this.tPayOrderMapper.selectByExample(tPayOrderExample);
        TPayOrder tPayOrder = tPayOrders.get(0);
        //修改支付状态
        tPayOrder.setPayState(OrderStateEnum.SM_FAIL.getCode());
        tPayOrder.setUpdatedAt(new Date());
        int sqlRowPayOrder = 0;
        sqlRowPayOrder = this.tPayOrderMapper.updateByPrimaryKeySelective(tPayOrder);
        StringBuffer buffer = new StringBuffer();
        //判断 是否更新成功
        if(sqlRowMainOrder == 1 && sqlRowPayOrder == 1){
            log.info("微信回调成功，接收到result_code 为FAIL， 更改状态为失败成功！");
            buffer.append("<xml>");
            buffer.append("<return_code>FAIL </return_code>");
            buffer.append("<return_msg>失败</return_msg>");
            buffer.append("<xml>");
        }
        return buffer;
    }

    private StringBuffer handleSuccess(SgsCallBackRequest sgsCallBackRequest, String outTradeNo) {

        //更新主订单
        TMainOrderExample tMainOrderExample = new TMainOrderExample();
        TMainOrderExample.Criteria criteria = tMainOrderExample.createCriteria();
        criteria.andOrderIdEqualTo(outTradeNo);
        List<TMainOrder> tMainOrders = this.tMainOrderMapper.selectByExample(tMainOrderExample);
        TMainOrder mainOrder = tMainOrders.get(0);

        //判读是否已经更新为成功状态
        if(OrderStateEnum.SM_SUC.getCode().equals(mainOrder.getOrderState())){
            return  getSucInfoResp();
        }
        //充值积分totalFee：分转元（保留两位小数）
        BigDecimal totalFee = AmountTransUtil.centToYuan(sgsCallBackRequest.getTotal_fee(),2);

        //修改支付状态
        mainOrder.setOrderState(OrderStateEnum.SM_SUC.getCode());
        mainOrder.setUpdatedAt(new Date());
        int sqlRowMainOrder = 0;
        //比较充值金额是否等于回调的总额
        if (mainOrder.getOrderAmount().compareTo(totalFee) == 0) {
            sqlRowMainOrder = this.tMainOrderMapper.updateByPrimaryKeySelective(mainOrder);
        }
        log.info("update main order：orderid={}, mainOrderAmount={}, callBackAmount={}, affected={}",
                outTradeNo, mainOrder.getOrderAmount(), sgsCallBackRequest.getTotal_fee(),
                sqlRowMainOrder);

        //更新支付单
        TPayOrderExample tPayOrderExample = new TPayOrderExample();
        TPayOrderExample.Criteria criteria1 = tPayOrderExample.createCriteria();
        criteria1.andOrderIdEqualTo(outTradeNo);
        List<TPayOrder> tPayOrders = this.tPayOrderMapper.selectByExample(tPayOrderExample);
        TPayOrder tPayOrder = tPayOrders.get(0);
        //修改支付状态
        tPayOrder.setPayState(OrderStateEnum.SM_SUC.getCode());
        tPayOrder.setUpdatedAt(new Date());
        int sqlRowPayOrder = 0;
        if (tPayOrder.getPayAmount().compareTo(totalFee) == 0) {
            sqlRowPayOrder = this.tPayOrderMapper.updateByPrimaryKeySelective(tPayOrder);
        }
        log.info("update pay order by orderid, orderid={}, mainOrderAmount={}, callBackAmount={}, affected={}",
                outTradeNo, mainOrder.getOrderAmount(), sgsCallBackRequest.getTotal_fee(), sqlRowPayOrder);

        //插入或者更新用户账户表
        TUserAccountExample tUserAccountExample = new TUserAccountExample();
        TUserAccountExample.Criteria tUserAccountExampleCriteria = tUserAccountExample.createCriteria();
        tUserAccountExampleCriteria.andUserIdEqualTo(tPayOrder.getUserId());
        List<TUserAccount> tUserAccounts = this.tUserAccountMapper.selectByExample(tUserAccountExample);
        TUserAccount tUserAccount = null;//用户账户
        if (CollectionUtils.isNotEmpty(tUserAccounts)) {
            tUserAccount = tUserAccounts.get(0);
        }

        //根据充值优惠规则得到优惠后的充值币数,只需要更新用户账户表，不需要更新订单，支付单表
        log.info("查询充值优惠规则前的金额{}",totalFee);
        BigDecimal userTotalFee = getUserTotalFee(sgsCallBackRequest,totalFee);
        log.info("查询充值优惠规则后的金额{}",userTotalFee);

        int sqlRowUserAccount = 0;
        if (tUserAccount == null) {
            tUserAccount = new TUserAccount();
            tUserAccount.setUserId(tPayOrder.getUserId());
            tUserAccount.setAccountAmount(userTotalFee);
            tUserAccount.setCreatedAt(new Date());
            tUserAccount.setAccountId(SeqUtil.getShortSeq(SeqFlagEnum.USER_ACCOUNT_ID.getCode()));
            sqlRowUserAccount = this.tUserAccountMapper.insertSelective(tUserAccount);
        } else {
            BigDecimal hisAccAmount = tUserAccount.getAccountAmount();//原有积分
            tUserAccount.setAccountAmount(hisAccAmount.add(userTotalFee));
            tUserAccount.setUpdatedAt(new Date());
            sqlRowUserAccount = this.tUserAccountMapper.updateByPrimaryKeySelective(tUserAccount);
        }
        log.info("更新用户账户余额:{}",tUserAccount);

        StringBuffer buffer = new StringBuffer();
        //判断 是否更新成功
        if(sqlRowMainOrder == 1 && sqlRowPayOrder == 1 && sqlRowUserAccount ==1){
            buffer = getSucInfoResp();
        }
        return buffer;
    }

    private StringBuffer getSucInfoResp() {
        StringBuffer buffer = new StringBuffer();
        log.info("微信回调处理成功：{}");
        buffer.append("<xml>");
        buffer.append("<return_code>SUCCESS</return_code>");
        buffer.append("<return_msg>OK</return_msg>");
        buffer.append("<xml>");
        return buffer;
    }


    /**
     * 根据充值优惠规则得到优惠后的充值币数
     * 100元130币，返回130
     * @param sgsCallBackRequest
     * @param originRechargeFee
     * @return
     */
    private BigDecimal getUserTotalFee(SgsCallBackRequest sgsCallBackRequest,BigDecimal originRechargeFee){
        SgsUserDiscRuleQueryRequest sgsUserDiscRuleQueryRequest = new SgsUserDiscRuleQueryRequest();
        sgsUserDiscRuleQueryRequest.setInitiationID(sgsCallBackRequest.getInitiationID());
        sgsUserDiscRuleQueryRequest.setReqTime(new Date());
        sgsUserDiscRuleQueryRequest.setLoginChannel(AppName.SGW.getNumber());
        SgsResultResponse<List<UserDiscountRuleVo>> sgsResultResponse = sgsUserDiscountRuleService.queryAllRule(sgsUserDiscRuleQueryRequest );
        if (sgsResultResponse != null ){
            List<UserDiscountRuleVo> list = sgsResultResponse.getResult();
            for ( UserDiscountRuleVo userDiscountRuleVo : list ){
                log.info("优惠规则: userDiscountRuleVo.getDiscountLevel() {}  VS  {}  and  userDiscountRuleVo.getDiscountAmount()=  {} ",
                        userDiscountRuleVo.getDiscountLevel(),  Integer.toString(originRechargeFee.intValue()), userDiscountRuleVo.getDiscountAmount()  );
                //注意这里的比较条件
                if (userDiscountRuleVo.getDiscountLevel().equals( Integer.toString(originRechargeFee.intValue()))){
                    BigDecimal userTotalFee =new BigDecimal(userDiscountRuleVo.getDiscountAmount()) ;
                    return userTotalFee;
                }
            }

        }
        return originRechargeFee ;

    }

    public static void main(String[] args){
        String strTotalFee = "211";
        BigDecimal totalFee = new BigDecimal(strTotalFee);
        BigDecimal totalFeeYuan = AmountTransUtil.centToYuan(strTotalFee,2);
        System.out.println(totalFee + "||" + totalFeeYuan);
    }
}

